namespace V2TEK.NET.SH.Silverlight.Calendar
{
    using System;

    internal sealed class Period : CalendarPeriod
    {
        private DateTime _endDate;
        private DateTime _startDate;

        public Period(WorkCalendar calendar, bool working, DateTime start, DateTime end) : base(calendar, working)
        {
            this._startDate = start.Date;
            this._endDate = end.Date;
            if (this._endDate < this._startDate)
            {
                throw new ArgumentException("start date after end date");
            }
        }

        internal override DateTime Add(DateTime time, ref long duration)
        {
            if (time < this._startDate)
            {
                throw new InvalidOperationException();
            }
            if (time > this._endDate.AddDays(1.0))
            {
                throw new InvalidOperationException();
            }
            if (duration != 0L)
            {
                if (!base._isWorking)
                {
                    return this._endDate.AddDays(1.0);
                }
                time = base.AddWorkInDay(time, ref duration);
                if (duration == 0L)
                {
                    return time;
                }
                TimeSpan span = (TimeSpan) (this._endDate - time.Date);
                int days = span.Days;
                if (days <= 0)
                {
                    return time;
                }
                long workInOneDay = base.WorkInOneDay;
                int num3 = (int) (duration / workInOneDay);
                int num4 = Math.Min(num3, days);
                if (num4 != 0)
                {
                    time = base._calendar._calendar.AddDays(time, num4);
                    duration -= workInOneDay * num4;
                    days -= num4;
                }
                if ((duration != 0L) && (days != 0))
                {
                    time = base.AddWorkInDay(time, ref duration);
                }
            }
            return time;
        }

        public override object Clone()
        {
            return (Period) base.MemberwiseClone();
        }

        public override bool Equals(object obj)
        {
            if (!(obj is Period))
            {
                return false;
            }
            Period period = (Period) obj;
            return ((((period._isWorking == base._isWorking) && period._endDate.Equals(this._endDate)) && period._startDate.Equals(this._startDate)) && period.SameWorkingTimes(this));
        }

        public override int GetHashCode()
        {
            return base.GetHashCode();
        }

        public bool Intersects(Period p)
        {
            return this.Intersects(p.StartDate, p.EndDate);
        }

        public bool Intersects(DateTime start, DateTime end)
        {
            return ((start.Date <= this._endDate) && (end.Date >= this._startDate));
        }

        internal override DateTime Remove(DateTime time, ref long duration)
        {
            if (time > this._endDate.AddDays(1.0))
            {
                throw new InvalidOperationException();
            }
            if (time < this._startDate)
            {
                throw new InvalidOperationException();
            }
            if (duration != 0L)
            {
                if (!base.IsWorking)
                {
                    return this._startDate;
                }
                time = base.RemoveWorkInDay(time, ref duration);
                if (duration == 0L)
                {
                    return time;
                }
                TimeSpan span = (TimeSpan) (time.Date - this._startDate);
                int days = span.Days;
                if (days == 0)
                {
                    return time;
                }
                long workInOneDay = base.WorkInOneDay;
                int num3 = (int) (duration / workInOneDay);
                int num4 = Math.Min(num3, days);
                if (num4 != 0)
                {
                    time = time.AddDays((double) -num4);
                    duration -= workInOneDay * num4;
                    days -= num4;
                }
                if ((duration != 0L) && (days != 0))
                {
                    time = base.RemoveWorkInDay(time, ref duration);
                }
            }
            return time;
        }

        internal long Work()
        {
            if (!base._isWorking)
            {
                return 0L;
            }
            return (this.NumberOfDays * base.WorkInOneDay);
        }

        internal override long WorkBetween(DateTime start, DateTime end)
        {
            if (start > end)
            {
                throw new ArgumentException();
            }
            if (start < this._startDate)
            {
                throw new ArgumentException();
            }
            if (end > this._endDate.AddDays(1.0))
            {
                throw new ArgumentException();
            }
            if ((start == end) || !base._isWorking)
            {
                return 0L;
            }
            DateTime date = end.Date;
            DateTime time2 = start.Date;
            if (date == time2)
            {
                return base.WorkBetweenHours(start, end);
            }
            long num = base.WorkBetweenHours(start, time2.AddDays(1.0));
            TimeSpan span = (TimeSpan) (date - time2);
            int num2 = span.Days - 1;
            if (num2 > 0)
            {
                num += num2 * base.WorkInOneDay;
            }
            return (num + base.WorkBetweenHours(date, end));
        }

        public DateTime EndDate
        {
            get
            {
                return this._endDate;
            }
            set
            {
                this._endDate = value;
            }
        }

        private int NumberOfDays
        {
            get
            {
                TimeSpan span = (TimeSpan) (this._endDate - this._startDate);
                return (span.Days + 1);
            }
        }

        public DateTime StartDate
        {
            get
            {
                return this._startDate;
            }
            set
            {
                this._startDate = value;
            }
        }
    }
}

